use std::fmt::Display;

use clap::{Parser, ValueEnum};

use crate::{analyzer::Analyzer, compiler::Compiler, token::Tokenizer};

#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
struct Args {
    #[arg(short, long,default_value_t = Target::Vm)]
    /// compile target
    target: Target,
    /// the path of jack file
    jack_file: String,
}
/// 参数设置动作
#[derive(Copy, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Default)]
enum Target {
    /// compile to vm.
    #[default]
    Vm,
    /// compile to token.
    Token,
    /// compile to xml.
    Grammar,
}
impl Display for Target {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let target = match self {
            Target::Vm => "vm",
            Target::Token => "token",
            Target::Grammar => "grammar",
        };
        write!(f, "{}", target)
    }
}

pub fn run() {
    let args = Args::parse();
    println!("- Compile file: {}", args.jack_file);

    match match args.target {
        Target::Token => Tokenizer::translate(args.jack_file),
        Target::Grammar => Analyzer::compile(&args.jack_file),
        Target::Vm => Compiler::compile(&args.jack_file),
    } {
        Ok(output_file) => println!(
            "- Output file: \n{}",
            output_file
                .iter()
                .map(|item| item.to_str().unwrap_or_default())
                .collect::<Vec<_>>()
                .join("\n")
        ),
        Err(e) => eprintln!("Error: {}", e),
    }
}
